package cn.mall.framework.biz;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import net.sf.json.JSONObject;

import org.apache.commons.lang.StringUtils;

import cn.mall.framework.biz.bean.BusinessException;
import cn.mall.framework.biz.bean.BusinessRequest;
import cn.mall.framework.biz.bean.BusinessResponse;
import cn.mall.framework.biz.bean.ErrorInfo;
import cn.mall.framework.common.BusinessContext;
import cn.mall.framework.common.FrameworkKit;
import cn.mall.framework.common.JsonKit;
import cn.mall.framework.common.Param;

@Slf4j
public class PublicServiceProcessAsyncImpl implements PublicServiceProcessAsync {
	
	@Resource
	private Map<String, PublicBusinessSystemServiceAsync<BusinessRequest, BusinessResponse>> servicesMap;
	@Resource
	private SendCallerMessageService sendCallerMessageService;

	protected void fillRequest(Object bean, JSONObject jsonObj) throws BusinessException {
		for (Class<?> clazz = bean.getClass(); !clazz.getName().equals(Object.class.getName()); clazz = clazz
				.getSuperclass()) {
			Field[] fields = clazz.getDeclaredFields();
			for (Field field : fields) {
				String fieldName = field.getName();
				String name = fieldName;
				String key = fieldName;
				boolean required = false;
				String format = null;
				int length = -1;
				int minLength = -1;
				int maxLength = -1;
				if (field.isAnnotationPresent(Param.class)) {
					Param param = field.getAnnotation(Param.class);
					String markKey = param.key();
					if (markKey != null && !markKey.equals("")) {
						key = markKey;
					}
					name = param.name();
					required = param.required();
					format = param.format();
					length = param.length();
					minLength = param.minLength();
					maxLength = param.maxLength();
				}
				String value = jsonObj.get(key) == null ? null : jsonObj.get(key).toString().trim();
				if (StringUtils.isBlank(value) && required)
					throw new BusinessException(name + "[" + key + "]不能为空");
				if (StringUtils.isNotBlank(value)) {
					if (length != -1) {
						if (value.length() != length)
							throw new BusinessException(name + "[" + key + "]长度必须为:" + length);
					}
					if (minLength != -1) {
						if (value.length() < minLength)
							throw new BusinessException(name + "[" + key + "]长度必须大于等于:" + minLength);
					}
					if (maxLength != -1) {
						if (value.length() > maxLength)
							throw new BusinessException(name + "[" + key + "]长度必须小于等于:" + maxLength);
					}
					fillValue(bean, field, key, jsonObj.get(key).toString(), name, required, format);
				}
			}
		}
	}

	protected Object buildObject(String string) throws BusinessException {
		Object o = null;
		try {
			o = Class.forName(string).newInstance();
		} catch (Exception e) {
			throw new BusinessException("反射[request="
					+ string + "]对象出错!", e);
		}
		return o;
	}

	protected void fillValue(Object bean, Field field, String key, String value, String name, boolean required,
			String format) throws BusinessException {
		String fieldName = field.getName();
		try {
			FrameworkKit.setFieldValueByTypeAndFormat(field, bean, value, format);
		} catch (Exception e) {
			e.printStackTrace();
			throw new BusinessException(fieldName + "转换出错", e);
		}
	}

	protected Method getMethodByName(Object bean, String setName) {
		Method[] ms = bean.getClass().getMethods();
		for (Method m : ms) {
			if (m.getName().equals(setName))
				return m;
		}
		return null;
	}

	@Override
	public String processRequest(Object object, String relationId,
			String srcUUID) {
		String json = (String) object;
		BusinessContext<BusinessRequest, BusinessResponse> context = new BusinessContext<BusinessRequest, BusinessResponse>();
		context.setRequestDate(new Date());
		context.setRelationId(relationId);
		context.setSrcUUID(srcUUID);
		PublicBusinessSystemServiceAsync<BusinessRequest, BusinessResponse> service = null;
		JSONObject jsonObj = null;
		try {
			jsonObj = JSONObject.fromObject(json);
			String msgId = jsonObj.getString("msgId");
			context.setMsgId(msgId);
			service = getServiceFromRequest(json);
			log.info(service.getTitle() + "请求数据:" + json);
			BusinessRequest businessRequest = (BusinessRequest) buildObject(getServiceRequest(service));
			context.setRequest(businessRequest);
			BusinessResponse businessResponse = (BusinessResponse) buildObject(getServiceResponse(service));
			context.setResponse(businessResponse);
			fillRequest(businessRequest, jsonObj);
			service.processRequest(context);
		} catch (BusinessException e) {
			sendError(context);
		} catch (Exception e) {
			log.info("", e);
			sendError(context);
		}
		return "OK";
	}
	
	private void sendError(BusinessContext<BusinessRequest, BusinessResponse> context) {
		Map<String, String> map = new HashMap<String, String>();
		map.put("errCode", ErrorInfo.INTERNAL_ERROR);
		map.put("errInfo", ErrorInfo.INTERNAL_ERROR_INFO);
		String responseString = JsonKit.map2json(map);
		sendToRequest(context, responseString);
	}
	
	private void sendToRequest(BusinessContext<BusinessRequest, BusinessResponse> context, String responseString) {
		String srcUUID = context.getSrcUUID();
		PublicBusinessSystemServiceAsync<?, ?> service = servicesMap.get(context.getMsgId());
		if (service != null) {
			log.info(service.getTitle() + "响应:" + responseString);
		} else {
			log.info("响应:" + responseString);
		}
		sendCallerMessageService.send(context.getRelationId(), responseString, srcUUID);
	}
	
	@SuppressWarnings({ "rawtypes", "unchecked" })
	private PublicBusinessSystemServiceAsync<BusinessRequest, BusinessResponse> getServiceFromRequest(String json)
			throws BusinessException {
		Map<String, String> requestMap = null;
		try {
			requestMap = JsonKit.jsonToMap(json);
		} catch (Exception e) {
			throw new BusinessException(ErrorInfo.INTERNAL_ERROR, ErrorInfo.INTERNAL_ERROR_INFO);
		}
		String msgId = requestMap.get("msgId"); // 消息类型
		if (StringUtils.isEmpty(msgId)) {
			log.error("[参数错误-服务编号为空]");
			throw new BusinessException(ErrorInfo.INTERNAL_ERROR, ErrorInfo.INTERNAL_ERROR_INFO);
		}
		PublicBusinessSystemServiceAsync service = servicesMap.get(msgId);
		if (service == null) {
			throw new BusinessException(ErrorInfo.INTERNAL_ERROR, "msgId:"+msgId+"未找到");
		}
		return service;
	}
	
	@SuppressWarnings("rawtypes")
	private String getServiceRequest(PublicBusinessSystemServiceAsync service) {
		Type type = service.getClass().getGenericSuperclass();
		ParameterizedType genericType = (ParameterizedType) type;
		Type p = genericType.getActualTypeArguments()[0];
		return p.toString().substring(p.toString().lastIndexOf(" ") + 1);
	}
	
	@SuppressWarnings("rawtypes")
	private String getServiceResponse(PublicBusinessSystemServiceAsync service) {
		Type type = service.getClass().getGenericSuperclass();
		ParameterizedType genericType = (ParameterizedType) type;
		Type p = genericType.getActualTypeArguments()[1];
		return p.toString().substring(p.toString().lastIndexOf(" ") + 1);
	}
}
